﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Weber.CS3280.Interfaces;
using Weber.CS3280.UI;
using Weber.CS3280.UI.ViewModels;

namespace Weber.CS3280.UI.ViewModels
{
	public abstract class ItemDetailViewModelBase : ViewModelBase
	{
		private bool _canSave;
		private bool _isDirty;
		private bool _isSaving;
		private string _errorMessage;
		private ICommand _editCommand;
		private ICommand _deleteCommand;
		private ICommand _saveCommand;
		private bool _showDelete;
		private bool _showSaveButtons = true;

		public string ErrorMessage
		{
			get { return _errorMessage; }
			set
			{
				if (_errorMessage == value)
					return;
				_errorMessage = value;
				NotifyPropertyChanged("ErrorMessage");
			}
		}

		public virtual string EditCommandDescription
		{
			get { return "Edit"; }
		}

		public virtual bool IsActive
		{
			get { return true; }
			set { }
		}

		protected abstract void Edit(Control control);

		protected virtual bool CanEdit(Control control)
		{
			return true;
		}

		public virtual string SaveCommandDescription
		{
			get { return "Save"; }
		}

		public bool IsSaving
		{
			get { return _isSaving; }
			set
			{
				if (_isSaving == value)
					return;
				_isSaving = value;
				NotifyPropertyChanged("IsSaving");
			}
		}

		protected async void SaveExecute(Control control)
		{
			if (!CanSave)
				return;

			try
			{
				IsSaving = true;
				// Let the container know that saving is occurring.
				await SaveAsync();

				Window window = Window.GetWindow(control);

				IModalWindow modalWindow = window as IModalWindow;

				if (modalWindow != null && modalWindow.IsModal)
					window.DialogResult = true;

				window.Close();
			}
			catch (Exception ex)
			{
				MessageBox.Show(Window.GetWindow(control),
					string.Format("An error occurred while saving: {0}", ex.Message), "Save Error", 
					MessageBoxButton.OK, MessageBoxImage.Error);
				return;
			}
			finally
			{
				IsSaving = false;
			}
		}

		/// <summary>
		/// Used to cancel an edit operation
		/// </summary>
		public virtual void Cancel() { }

		public abstract void Save();

		public Task SaveAsync()
		{
			return Task.Run(() => Save());
		}

		public bool CanSave
		{
			get { return _canSave; }
			set
			{
				if (_canSave == value)
					return;
				_canSave = value;
				NotifyPropertyChanged("CanSave");
			}
		}

		public virtual string DeleteCommandDescription
		{
			get { return "Delete"; }
		}

		protected virtual void Delete(Control control)
		{
		}

		protected virtual bool CanDelete(Control control)
		{
			return ShowDelete;
		}

		public bool ShowDelete
		{
			get { return _showDelete; }
			set
			{
				if (_showDelete == value)
					return;
				_showDelete = value;
				NotifyPropertyChanged("ShowDelete");
			}
		}

		public bool ShowSaveButtons
		{
			get { return _showSaveButtons; }
			set
			{
				if (_showSaveButtons == value)
					return;
				_showSaveButtons = value;
				NotifyPropertyChanged("ShowSaveButtons");
			}
		}

		public ICommand EditCommand
		{
			get
			{
				if (_editCommand == null)
					_editCommand = new RelayCommand(p => Edit(p as Control), p => CanEdit(p as Control));

				return _editCommand;
			}
		}

		public ICommand DeleteCommand
		{
			get
			{
				if (_deleteCommand == null)
					_deleteCommand = new RelayCommand(p => Delete(p as Control), p => CanDelete(p as Control));

				return _deleteCommand;
			}
		}

		public ICommand SaveCommand
		{
			get
			{
				if (_saveCommand == null)
					_saveCommand = new RelayCommand(p => SaveExecute(p as Control));

				return _saveCommand;
			}
		}

		public virtual bool IsDirty
		{
			get { return _isDirty; }
			set
			{
				if (_isDirty == value)
					return;
				_isDirty = value;
				NotifyPropertyChanged("IsDirty");
			}
		}

		protected virtual bool Validate()
		{
			return true;
		}

		protected virtual string BuildErrorMessage()
		{
			return string.Empty;
		}

		protected override void NotifyPropertyChanged(string propertyName, object passThroughSender = null)
		{
			// Check to see if the item is allowed to save
			CanSave = Validate();
			// If not, then build an error message
			ErrorMessage = CanSave ? string.Empty : BuildErrorMessage();

			base.NotifyPropertyChanged(propertyName, passThroughSender);
		}
	}
}
